package com.ck.client.controller;

import com.ck.client.service.BindService;
import com.ck.common.model.OperationResult;
import com.ck.client.model.vo.DeviceBindMsg;
import com.ck.core.lock.LockConstant;
import com.ck.core.lock.RedisDistributeLock;
import com.ck.core.lock.RedisLock;
import com.ck.core.util.HttpUtils;
import com.ck.core.util.JWTUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.regex.Pattern;

/**
* @Description: 设备与门店绑定，实质是向ck_device_store表插入一条设备与门店（商家）的关联关系
 *             // 经过绑定的设备才是能与后台进行交互的合法设备
 *             // 绑定后才去做注册、轮训上报的流程
 *             // ...
* @Author: hf
* @Date:    2019/4/23 14:27
* @Version: 1.0
*/
@Controller
public class BindDeviceController {
	private static Logger logger = LoggerFactory.getLogger(BindDeviceController.class);
	/** 数字验证正则表达式 */
	private static final Pattern DIGIT_PATTERN = Pattern.compile("^[-\\+]?[\\d]*$");
	/** 设备序列号默认长度 */
	private static final int DEFAULT_DEVICE_SERIAL_NUM = 8;
	@Autowired
	private BindService bindService;
	@Autowired
	private RedisDistributeLock distributeLock;
	/**
	 * 设备与门店（商家）进行绑定
	 *   // 该接口允许跨域访问（h5绑定时触发）
	 * @param request
	 * @return
	 */
	@CrossOrigin
	@ResponseBody
	@PostMapping(value = "/bind")
	public OperationResult<Object> bind(HttpServletRequest request) {

		// 设备唯一code码
		String deviceCode = request.getHeader("devicecode");
		// 外网ip
		String ip = HttpUtils.getRemortIP(request);
		// 设备mac
		String mac = request.getHeader("mac");
		// 通过序列号绑定
		String serialNum = request.getParameter("serialNum");

		// 以下字段只有通过二维码登录使用token绑定的方式才会有意义
		// token
		String token = request.getHeader("token");
		// 设备序列号地
		String deviceSerialNum = request.getParameter("deviceSerialNum");
		// 设备类型（横屏、竖屏）
		String deviceType = request.getParameter("deviceType");
		// 楼层
		String floor = request.getParameter("floor");
		// 详细位置
		String position = request.getParameter("position");
		// 门店id
		String storeId = request.getParameter("storeId");
		//设备型号
		String model = request.getParameter("model");
		//设备尺寸
		String screenSize = request.getParameter("screenSize");
		//楼栋
		String building = request.getParameter("building");
		//单元
		String unit = request.getParameter("unit");
		//设备名称
		String deviceName = request.getParameter("deviceName");

		if ( StringUtils.isBlank(deviceCode) ) {
			return OperationResult.newValidateFailOperationResult("设备唯一编码不能为空");
		}
		try (RedisLock lock = distributeLock.getLock(LockConstant.DEVICE_BIND_LOCK_PREFIX,
				LockConstant.DEFAULT_TIMEOUT_MILLS, LockConstant.MAX_RETRY_TIMES, LockConstant.RETRY_INTERVAL_TIME_MILLIS)) {
			if (null != lock) {
				if ( bindService.isDeviceCodeBinded(deviceCode) ) {
					return OperationResult.newSuccessOperationResult("设备已经被绑定，无需再次绑定");
				}
				// 1、序列号绑定方式
				if (  StringUtils.isNotBlank(serialNum) ) {
					logger.info("{}.执行序列号绑定逻辑。序列号为:{}",deviceCode,serialNum);
					return serialNumBind(serialNum,deviceCode);
				}

				// 2、二维码登录门店帐号通过token的方式绑定
				if ( StringUtils.isNotBlank(token) ) {
					logger.info("{}.执行二维码登录，token绑定设备逻辑。参数为:{},{},{},{},{},{}", deviceCode,token, deviceType, floor, position,deviceSerialNum,storeId);
					return tokenBind(token,deviceCode,deviceType,floor,position,deviceSerialNum,storeId,model,building,screenSize,unit,deviceName);
				}

				boolean bindStatus ;

				// 3、通过mac地址匹配的方式绑定
				if ( StringUtils.isNotBlank(mac) ) {
					logger.info("{}.执行mac绑定逻辑,mac地址为{}:",deviceCode,mac);
					bindStatus = macBind(mac,deviceCode);
					if ( bindStatus ) {
						return OperationResult.newSuccessOperationResult("通过mac绑定门店成功");
					}
				}

				// 4、通过网关ip的方式绑定
				/*if ( StringUtils.isNotBlank(ip)) {
					logger.info("{}.执行网关ip绑定逻辑,ip地址为{}:",deviceCode,ip);
					return  ipBind(ip,deviceCode);
				}*/
				logger.info("{}所有尝试所有绑定方式均失败",deviceCode);
				return OperationResult.newValidateFailOperationResult("绑定失败！请检查参数");
			} else {
				return OperationResult.newValidateFailOperationResult("网络繁忙，请稍候再试");
			}
		}catch (Exception e) {
			logger.error(e.getMessage(),e);
			return OperationResult.newSystemErrorOperationResult();
		}

	}

	private boolean macBind(String mac, String deviceCode) {
		Long storeId = bindService.getStoreIdWithMac(mac);
		if ( storeId != null ) {
			String serialNum = bindService.generateDeviceSerialNum(storeId);
			return bindService.macBind(mac, deviceCode, serialNum);
		}
		return false;
	}

	private OperationResult<Object> tokenBind(String token, String deviceCode, String deviceType, String floor, String position, String deviceSerialNum, String storeId,String model,String building,String screenSize,String unit,String deviceName) {
		try {
			JWTUtils.parseJWTToken(token).get("userName").asString();
		}catch (Exception e) {
			logger.error(e.getMessage(),e);
			return OperationResult.newValidateFailOperationResult("token不正确，请重新登录");
		}
		if ( StringUtils.isBlank(storeId) ) {
			return OperationResult.newValidateFailOperationResult("请选择门店");
		}
		if ( StringUtils.isBlank(deviceSerialNum) || !DIGIT_PATTERN.matcher(deviceSerialNum).matches()){
			return OperationResult.newValidateFailOperationResult("序列号不能为空，设备序列号数字");
		}
		String storeSerialNum = bindService.getSerialNumByStoreId(Long.valueOf(storeId));
		if ( StringUtils.isBlank(storeSerialNum) ) {
			return OperationResult.newValidateFailOperationResult("门店信息不存在或已被禁用");
		}
		String serialNum =  storeSerialNum + deviceSerialNum;
		if ( serialNum.length() != DEFAULT_DEVICE_SERIAL_NUM  && DIGIT_PATTERN.matcher(serialNum).matches()){
			return OperationResult.newValidateFailOperationResult("序列号格式不正确");
		}
		Boolean existed = bindService.deviceSerialNumExisted(Long.valueOf(storeId), serialNum);
		if ( existed ) {
			return OperationResult.newValidateFailOperationResult("该序列号已被使用");
		}
		DeviceBindMsg bindMsg = new DeviceBindMsg();
		bindMsg.setDeviceCode(deviceCode);
		bindMsg.setDeviceSerialNum(serialNum);
		bindMsg.setStoreId(Long.valueOf(storeId));
		bindMsg.setDeviceType(deviceType);
		bindMsg.setFloor(floor);
		bindMsg.setPosition(position);
		bindMsg.setBuilding(building);
		bindMsg.setDeviceName(deviceName);
		bindMsg.setUnit(unit);
		bindMsg.setScreenSize(screenSize);
		bindMsg.setModel(model);
		return bindService.bind(bindMsg);
	}

	private OperationResult<Object> serialNumBind(String serialNum, String deviceCode) {
		if ( serialNum.length() != DEFAULT_DEVICE_SERIAL_NUM  && DIGIT_PATTERN.matcher(serialNum).matches()){
			return OperationResult.newValidateFailOperationResult("序列号需为8为数字");
		}

		String storeSerialNum = serialNum.substring(0,4);
		Long storeId = bindService.getStoreIdBySerialNum(storeSerialNum);
		if ( storeId == null ) {
			return OperationResult.newValidateFailOperationResult("门店信息不存在或已被禁用");
		}
		Boolean existed = bindService.deviceSerialNumExisted(storeId, serialNum);
		if ( existed ) {
			return OperationResult.newValidateFailOperationResult("该序列号已被使用");
		}
		DeviceBindMsg bindMsg = new DeviceBindMsg();
		bindMsg.setDeviceCode(deviceCode);
		bindMsg.setDeviceSerialNum(serialNum);
		bindMsg.setStoreId(storeId);
		return bindService.bind(bindMsg);
	}

	private OperationResult ipBind(String ip, String deviceCode) {

		Long storeId = bindService.getStoreIdWithRecentlyIP(ip);
		if ( storeId != null ) {

			DeviceBindMsg bindMsg = new DeviceBindMsg();
			bindMsg.setDeviceCode(deviceCode);
			bindMsg.setStoreId(storeId);
			String serialNum = bindService.generateDeviceSerialNum(storeId);
			bindMsg.setDeviceSerialNum( serialNum );
			return bindService.bind(bindMsg);
		}
		return OperationResult.newValidateFailOperationResult("绑定失败！系统不存在该ip的访问记录");
	}

}
